package com.evil.account.strategy.login;

import cn.hutool.core.bean.BeanUtil;
import com.evil.account.enums.login.AuthTypeEnum;
import com.evil.account.mapper.EnterpriseMapper;
import com.evil.account.mapper.UserEnterpriseMapper;
import com.evil.account.pojo.entity.*;
import com.evil.account.service.*;
import com.evil.account.service.impl.AccountLogServiceImpl;
import com.evil.account.util.EnterpriseUtil;
import com.evil.account.util.UserUtil;
import com.evil.common.account.bo.AuthUserBO;
import com.evil.common.account.dto.LoginReqDTO;
import com.evil.common.account.dto.user.UserEnterpriseDTO;
import com.evil.common.account.enums.PlatformTypeEnum;
import com.evil.common.core.dto.FindByIdsReqDTO;
import com.evil.common.core.enums.RCodeEnum;
import com.evil.common.core.enums.SwitchEnum;
import com.evil.common.core.exception.BusinessException;
import com.evil.common.core.util.PasswordUtil;
import com.evil.common.core.util.StreamUtil;
import com.evil.file.api.RemoteFileService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author liyang
 * @date 2022-08-08 00:00
 */
@Slf4j
@Service
@AllArgsConstructor
public class AccountAuthImpl implements AuthService, AuthUserService {

    private final UserService userService;

    private final UserEnterpriseMapper userEnterpriseMapper;

    private final EnterpriseMapper enterpriseMapper;

    private final TokenService tokenService;

    private final AccountLogServiceImpl logService;

    private final UserDepartmentService userDepartmentService;

    private final DepartmentService departmentService;

    private final UserRoleService userRoleService;

    private final RoleService roleService;

    private final RemoteFileService fileService;

    /**
     * 登录类型
     *
     * @return AuthTypeEnum
     */
    @Override
    public AuthTypeEnum type() {
        return AuthTypeEnum.ACCOUNT;
    }

    /**
     * 登录
     *
     * @param loginReqDTO loginReqDTO
     * @return AuthUserBO
     */
    @Override
    public AuthUserBO login(LoginReqDTO loginReqDTO) {
        User user = userService.getBaseMapper().isExistByTel(loginReqDTO.getTel())
                .orElseThrow(() -> new BusinessException(RCodeEnum.PASSWORD_ERROR));
        UserUtil.validUser(user);

        // 校验密码
        String secretPassword = PasswordUtil.getSecretPassword(loginReqDTO.getPassword(), user.getSalt());
        if (StringUtils.isBlank(secretPassword)) {
            throw new BusinessException(RCodeEnum.PASSWORD_ERROR);
        }
        if (!secretPassword.equalsIgnoreCase(user.getPassword())) {
            throw new BusinessException(RCodeEnum.PASSWORD_ERROR);
        }
        PlatformTypeEnum platformTypeEnum = PlatformTypeEnum.findById(loginReqDTO.getPlatformType());
        UserEnterprise userEnterprise = null;
        switch (platformTypeEnum) {
            // 总后台登录校验
            case ADMIN_PLATFORM:
                List<UserEnterprise> userEnterprises = userEnterpriseMapper.findUserEnterprises(user.getUserId(), null);
                for (UserEnterprise ue : userEnterprises) {
                    boolean sign = enterpriseMapper.isExistById(ue.getEnterpriseId())
                            .filter(EnterpriseUtil::checkEnterprise)
                            .map(Enterprise::getPlatformType)
                            .map(e -> platformTypeEnum.getId() == e).orElse(false);
                    if (sign) {
                        userEnterprise = ue;
                        break;
                    }
                }
                break;
            // 企业后台校验
            case ENTERPRISE:
                Integer platformType = PlatformTypeEnum.ENTERPRISE.getId();
                // 设置默认企业
                userEnterprise = userEnterpriseMapper.findPlatformDefaultByUserId(user.getUserId(), platformType).orElse(null);
                // 如果默认企业为空，则随便取出一个企业进行登录
                if (null == userEnterprise) {
                    // 在非默认企业中随意取出一个未禁用的企业进行登录
                    userEnterprise = userEnterpriseMapper.findPlatformOneByUserId(user.getUserId(), platformType).orElse(null);
                }
                break;
            default:
                throw PlatformTypeEnum.getBusinessException();
        }

        if (null == userEnterprise) {
            throw new BusinessException(RCodeEnum.ERROR_RUNTIME, "用户没有关联企业");
        }
        loginReqDTO.setEnterpriseId(userEnterprise.getEnterpriseId());
        // 封装Bo
        Enterprise enterprise = enterpriseMapper.findById(loginReqDTO.getEnterpriseId());

        // 创建token
        String token = tokenService.create(user, enterprise);
        AuthUserBO authUserBaseInfo = this.getAuthUserBaseInfo(user, token, enterprise);
        // 修改默认企业
        this.modifyDefaultEnterprise(userEnterprise);
        return authUserBaseInfo;
    }

    /**
     * 构建AuthUserBO
     *
     * @param user       user
     * @param token      token
     * @param enterprise 企业
     * @return return
     */
    @Override
    public AuthUserBO getAuthUserBaseInfo(User user, String token, Enterprise enterprise) {
        AuthUserBO authUserBO = BeanUtil.copyProperties(user, AuthUserBO.class);
        authUserBO.setToken(token);
        authUserBO.setEnterpriseId(enterprise.getEnterpriseId());
        authUserBO.setEnterpriseName(enterprise.getEnterpriseName());
        if (null != user.getPortraitFileId()) {
            fileService.isExistBaseByFileId(user.getPortraitFileId()).ifPresent(f -> authUserBO.setPortraitFileUrl(f.getFileUrl()));
        }
        authUserBO.setSystemName(enterprise.getSystemName());
        if (null != enterprise.getSystemLogoFileId()) {
            fileService.isExistBaseByFileId(enterprise.getSystemLogoFileId())
                    .ifPresent(f -> authUserBO.setSystemLogoFileUrl(f.getFileUrl()));
        }
        return this.queryUserInfo(authUserBO);
    }

    /**
     * 修改用户默认企业
     *
     * @param userEnterprise userEnterprise
     */
    @Override
    public void modifyDefaultEnterprise(UserEnterprise userEnterprise) {
        // 若是企业端登录
        if (enterpriseMapper.findById(userEnterprise.getEnterpriseId()).getPlatformType().equals(PlatformTypeEnum.ENTERPRISE.getId())) {
            // 获取总后台企业
            List<Enterprise> adminEnterprise = enterpriseMapper.findListByPlatformType(PlatformTypeEnum.ADMIN_PLATFORM.getId());
            List<Long> adminEnterpriseIds = adminEnterprise.stream().map(Enterprise::getEnterpriseId).collect(Collectors.toList());
            // 设置其他企业不是管理员
            userEnterpriseMapper.findUserEnterprises(userEnterprise.getUserId(), null).stream()
                    // 过滤总后台的企业 && 过滤出是默认企业的用户企业信息
                    .filter(ue -> !adminEnterpriseIds.contains(ue.getEnterpriseId()) && SwitchEnum.isOpen(ue.getIsDefault()))
                    // 其他的全部设置为 不是默认企业
                    .forEach(u -> {
                        u.setIsDefault(SwitchEnum.NO.getId());
                        logService.saveAndCheck(userEnterpriseMapper, UserEnterprise::getUserEnterpriseId, u);
                    });
            // 设置默认企业
            userEnterprise.setIsDefault(SwitchEnum.YES.getId());
            logService.saveAndCheck(userEnterpriseMapper, UserEnterprise::getUserEnterpriseId, userEnterprise);
        }
    }

    /**
     * 补充用户信息
     *
     * @param authUserBO 返回bo
     * @return AuthUserBO
     */
    public AuthUserBO queryUserInfo(AuthUserBO authUserBO) {
        UserEnterpriseDTO userEnterpriseDTO = new UserEnterpriseDTO(authUserBO.getEnterpriseId(), authUserBO.getUserId());

        // 所属部门列表
        List<UserDepartment> userDepartments = userDepartmentService.findByEnterpriseUser(userEnterpriseDTO);
        Set<Long> departmentIds = StreamUtil.transSetT(userDepartments, UserDepartment::getDepartmentId);
        authUserBO.setDepartments(departmentService.findBaseByIds(FindByIdsReqDTO.filter(departmentIds)));

        // 所属角色列表
        List<UserRole> userRoles = userRoleService.findByEnterpriseUser(userEnterpriseDTO);
        Set<Long> roleIds = StreamUtil.transSetT(userRoles, UserRole::getRoleId);
        authUserBO.setRoles(roleService.findBaseByIds(FindByIdsReqDTO.filter(roleIds)));

        return authUserBO;
    }
}
